package com.devin.avatar.common.util;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

public class JsonUtil {
    private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);

    private static ObjectMapper mapper = new ObjectMapper();

    static {
	// 设置时区
	mapper.setTimeZone(TimeZone.getDefault());
	// 设置日期格式
	mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
	// 序列化设置,序列化成json字符串的时候不包含null值,针对POJO类
	mapper.setSerializationInclusion(Include.NON_NULL);

	// 允许单引号、允许不带引号的字段名称
	mapper.enable(Feature.ALLOW_SINGLE_QUOTES);
	mapper.enable(Feature.ALLOW_UNQUOTED_FIELD_NAMES);
	// 忽略JSON字符串中存在而Java对象实际没有的属性
	mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

	//JSR310支持LocalDateTime
	JavaTimeModule javaTimeModule = new JavaTimeModule();
	javaTimeModule.addSerializer(LocalDateTime.class,
		new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
	javaTimeModule.addSerializer(LocalDate.class,
		new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
	javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
	javaTimeModule.addDeserializer(LocalDateTime.class,
		new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
	javaTimeModule.addDeserializer(LocalDate.class,
		new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
	javaTimeModule.addDeserializer(LocalTime.class,
		new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
	
	mapper.registerModule(javaTimeModule);
    }

    private JsonUtil() {
    }

    public static ObjectMapper getObjectMapper() {
	return mapper;
    }

    /**
     * 序列化为String
     */
    public static String toJsonString(Object object) {
	try {
	    return mapper.writeValueAsString(object);
	} catch (Exception e) {
	    logger.warn("write to json string error:" + object, e);
	    throw new RuntimeException("JsonUtil.toJsonString发生错误", e);
	}
    }

    /**
     * 反序列化为Object
     */
    public static <T> T toObject(String jsonString, Class<T> clazz) {
	if (StringUtils.isEmpty(jsonString)) {
	    return null;
	}
	try {
	    return mapper.readValue(jsonString, clazz);
	} catch (Exception e) {
	    logger.warn("parse json string error:" + jsonString, e);
	    throw new RuntimeException("JsonUtil.toObject发生错误", e);
	}
    }

    /**
     * 反序列化为List
     */
    public static <T> List<T> toList(String jsonString, Class<T> clazz) {
	try {
	    return mapper.readValue(jsonString, createCollectionType(List.class, clazz));
	} catch (Exception e) {
	    logger.warn("parse json string error:" + jsonString, e);
	    throw new RuntimeException("JsonUtil.toList发生错误", e);
	}
    }

    /**
     * 反序列化为Map
     */
    public static <K, V> Map<K, V> toMap(String jsonString, Class<K> keyCls, Class<V> valueCls) {
	try {
	    return mapper.readValue(jsonString, createCollectionType(Map.class, keyCls, valueCls));
	} catch (Exception e) {
	    logger.warn("parse json string error:" + jsonString, e);
	    throw new RuntimeException("JsonUtil.toMap发生错误", e);
	}
    }

    /**
     * 将json字符串反序列化为Array
     */
    public static <T> T[] toArray(String jsonString, Class<T> clazz) {
	try {
	    return mapper.readValue(jsonString, mapper.getTypeFactory().constructArrayType(clazz));
	} catch (Exception e) {
	    logger.warn("parse json string error:" + jsonString, e);
	    throw new RuntimeException("JsonUtil.toArray发生错误", e);
	}
    }

    /**
     * 构造泛型的Collection Type如: ArrayList<MyBean>,
     * 则调用constructCollectionType(ArrayList.class,MyBean.class)
     * HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class)
     */
    public static JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
	return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    public static void main(String[] args) {
	Map map = new HashMap<>();
	map.put("k1", LocalDate.now());

	String json = JsonUtil.toJsonString(map);
	System.out.println(json);
	
	map = JsonUtil.toObject(json, Map.class);
	System.out.println("k1=" + map.get("k1"));
	System.out.println("k1.class=" + map.get("k1").getClass());
	
	map = JsonUtil.toMap(json, String.class, LocalDate.class);
	System.out.println("k1=" + map.get("k1"));
	System.out.println("k1.class=" + map.get("k1").getClass());
    }
}
